#/*************************************************************************
#    > File Name: File_Operation.py
#    > Author: Yan Wang
#    > Mail: wangyan@imnu.edu.cn
#    > Created Time: 2022年04月09日 星期六 17时17分07秒
# ************************************************************************/
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Library import *
from Folder_Operation import *
from List_Operation import *

# 返回文件名
def Get_File_Name(path_name):
    path = Path(path_name)
    return(os.path.basename(path))   #os.path.basename(path)用于获取指定路径中的基名称--path的最后一个文件名称，以字符串的形式出现

# 返回文件名
def Get_File_Name_without_Ext(path_name):
    path = Path(path_name)
    return(path.stem)   #os.path.basename(path)用于获取指定路径中的基名称--path的最后一个文件名称，以字符串的形式出现

# 将文件名中添加 _{} ， 便于后续扩展为其他类似的文件名
def File_Name_Generalizing(file_name):
    basename = Get_File_Name(file_name)
    name_list=basename.split(".",2)  #.split()通过指定分隔符对字符串进行切片,"."为分隔符，“2”分割次数
    new_name=name_list[0]+"_{}."+name_list[1]   #在文件后面加入_{}.+扩展名
    return(new_name)


#根据输入的文件名 orginal_file， 复制生成多个子文件
#输出为生成的文件的文件名
def Copy_File(source_file, target_file):
    try:
        if os.path.isdir(source_file) | os.path.isdir(target_file):   ##os.path.isdir()判断()是否为目录,“|”--“或”
            if os.path.exists(target_file):  #os.path.exists()判断括号里的文件是否存在,存在返回True，否则返回False
                if not os.listdir(target_file):
                    os.rmdir(target_file)
                else:
                    ii = 1
                    while True:
                        new_name = os.path.realpath(target_file)+ "_" +str(ii)   #os.path.realpath()获取当前执行脚本的绝对路径
                        if not os.path.exists(new_name):
                            shutil.move(target_file, new_name)   #shutil.move(A,B)将文件或目录A递归移动到B并返回B
                            print("Backup old", target_file, "as", new_name)
                            break 
                        ii += 1
            shutil.copytree(source_file,target_file)   #shutil.copytree()可以递归copy多个目录到指定目录下--将source_file目标文件内的内容复制到target_file中
        elif os.path.isfile(source_file) | os.path.isfile(target_file):   #os.path.isfile()判断()是否为文件
            shutil.copy(source_file,target_file)   #shutil.copy(A,B)实现文件复制功能,A复制到B中
    except IOError as e:
        try:
            print('Unable to copy file. %s' % e)
        finally:   #当try块中代码为发生异常时，except块不会执行，else块和finally块中的代码会被执行。
            e = None
            del e
    except:
        print('Unexpected error:', sys.exc_info())
    print('Copy ', source_file, " to ", target_file)
    return(target_file)


#将source_file移动到target_file并返回target_file，否则出现语法提示或报错
def Move_File(source_file, target_file):
    try:
        shutil.move(source_file,target_file)
    except IOError as e:
        try:
            print('Unable to move file. %s' % e)
        finally:
            e = None
            del e
    except:
        print('Unexpected error:', sys.exc_info())
    return(target_file)


# 定义函数——文件替换
def File_Replace(fname, linenos=[], strings=[]):
    #"" 
# Insert several strings to lines with linenos repectively. 
# The elements in linenos must be in increasing order and len(strings) 
# must be equal to or less than len(linenos). 
# 
# The extra lines ( if len(linenos)> len(strings)) will be inserted 
# with blank line. 
#""
    if os.path.exists(fname):
        lineno = 0
        i = 0
        for line in fileinput.input(fname, inplace=1):   #fileinput.input()返回能够用于for循环遍历的对象，fname多个文件的路径列表,inplsce=1：文件将被移动到备份文件，标准输出将被定向到输入文件
            # inplace must be set to 1 
# it will redirect stdout to the input file 
            lineno += 1
#line = line.strip() 
            line = line.rstrip('\n')   #rstrip() 删除 string 字符串末尾的指定字符，默认为空白符，包括空格、换行符、回车符、制表符。
            if i < len(linenos) and linenos[i] == lineno:
                if i >= len(strings):
                    print('\n', line)
                else:
                    print(strings[i])
                i += 1
            else:
                print(line)
    else:
        print("Error in File_Replace: no such file ", fname)


# 定义函数——文件插入
def File_Insert(fname, linenos=[], strings=[]):
    if os.path.exists(fname):
        lineno = 0
        i = 0
        for line in fileinput.input(fname, inplace=1):
            # inplace must be set to 1 
      # it will redirect stdout to the input file 
            lineno += 1
            line = line.strip()
            if i < len(linenos) and linenos[i] == lineno:
                if i >= len(strings):
                    print('\n', line)
                else:
                    print(strings[i])
                    print(line)
                i += 1
            else:
                print(line)





# 生成同一类文件的文件名列表
# 返回为target_folder/general_name(1-filelength)列表
def Generate_General_NameList(general_name, target_folder, file_num_list):
    general_file_name=os.path.basename(general_name)
    name_list = []
    if isinstance(file_num_list, int):
        file_num_list=np.arange(file_num_list)+1
    for file_num in file_num_list:
        format_num=str(file_num).rjust(2,"0")
        target = general_file_name.format(format_num)
        target = os.path.join(target_folder, target)
        name_list.append(target)

    return(name_list)


# 根据通用名，一次生成多个文件：
def Create_MultiFile(file_num_list, file_general_name, target_folder, original_file):
    file_name_list=Generate_General_NameList(file_general_name,target_folder,file_num_list)   #创建target_folder/general_name(1-filelength)列表
    #print(file_name_list)
    [Copy_File(original_file, target) for target in file_name_list]
    return(file_name_list)





# 整合几个常用函数， 给定文件， 在指定文件夹生成多个文件
def Copy_Multi_File(file_num_list, source, output_file_name):
    #print("output_file_name",output_file_name)
    output_folder = os.path.dirname(output_file_name)   #os.path.dirname()用于从指定路径获取目录（不带最后的基文件）名称
    #print("output_folder",output_folder)
    target_folder = Create_Folder(output_folder)   #创建文件夹，output_folde/source(无后缀名)
    output_files = Create_MultiFile(file_num_list, output_file_name, target_folder, source)   #一次copy多个target_folder/output_file_name(1-num)文件
    return(output_files)


# 将当前按照顺序命名的文件，从一个新的起始顺序开始重新命名
# 例如：name_series="05", 则将 target_file_name=run_01_tag_1_banner.dat 改为 run_05_tag_1_banner.dat
def Rename_Series_Files(name_series,target_file_name,split_pattern="_",num=1):
    if not os.path.exists(target_file_name):
        print("Error in Rename_Series_Files: no such file:", target_file_name)
        exit(0)
    pattern="(?P<value>\d+)"   #为以下sub()函数铺垫，替换的是value
    dirname=os.path.dirname(target_file_name)
    basename=os.path.basename(target_file_name)
    seperatename=basename.split(split_pattern)   #对basename以"_"进行切片处理
    seperatename_n=seperatename[num]
    new_seperatename_n=re.sub(pattern,name_series,seperatename_n,count=1)   #re.sub(A,B,C,D)A表示表示正则中的模式字符串,B表示替换的字符串或函数，C要被替换的那个字符串或函数，count=1代表只处理第一组value
    seperatename[num]=new_seperatename_n
    new_basename=split_pattern.join(seperatename)
    new_dir=os.path.join(dirname,new_basename)
    Move_File(target_file_name, new_dir)





# 将run_**文件夹中的文件，包含tag_n_***的统一改为tag_1
# 可以写为： print(Multi_Rename_Series_Files("tag_\d+",test_folder,"tag_1"))
# 输入的是 Path类型的完整路径列表, pattern应该包含正则表达式，从而包含所有想要的替换文件名

def Multi_Rename_Series_Files(pattern,folder_name,repl,count=0):
    new_files=[]
    files=Find_File(folder_name,pattern)
    for this_file in files:
        #re.search()一种字符串匹配方法，pattern匹配到this_file的基文件   
        #pos=re.search(pattern,os.path.basename(this_file))
        #if (pos != None):
        new_file=re.sub(pattern,repl,this_file,count)  #count=0代表所有的匹配都会被替换；
        Move_File(this_file,new_file)
        new_files.append(this_file)
    return(new_files)


#原文件夹中包含若干子文件夹，子文件夹中包含命名相似的文件，将其统一移动到一个新文件夹中
# 只处理子文件夹中的文件，不处理当前文件夹下的文件
# 
def Move_Series_Files(File_General_Name,Origin_File_Name,Origin_Folder_Name, Target_Folder_Name):
    file_name_list=[]
    # 如果Target_Folder 不存在则创建， 之后原文件会被拷贝到Target——Folder中
    if not os.path.exists(Target_Folder_Name):
        Create_Folder(Target_Folder_Name,"/")
    #针对源文件夹，做循环， 只寻找文件夹
    for sub_folder in Path(Origin_Folder_Name).iterdir():
        if not sub_folder.is_dir():   #is_dir()检查指定文件夹是否为一个目录
            continue
        # 提取序号， 进行相加
        folder_num=sub_folder.name.split("_",2)[1]
        event_file=File_General_Name.format(folder_num)
        target_file=Origin_File_Name.format(folder_num)
        sub_folder=os.path.basename(sub_folder)
        original_file=os.path.join(Origin_Folder_Name,sub_folder,target_file)
        this_event_file=os.path.join(Target_Folder_Name,event_file)
        file_name_list.append(this_event_file) 
        Copy_File(original_file, this_event_file)
    return(file_name_list)

def Move_Series_Files_bk(File_General_Name,Origin_File_Name,Origin_Folder_Name, Target_Folder_Name):
    file_name_list=[]
    for sub_folder in Path(Origin_Folder_Name).iterdir():
        #print(sub_folder)
        if not sub_folder.is_dir():
            continue
        folder_num=sub_folder.name.split("_",2)[1]
        event_file=File_General_Name.format(folder_num)
        target_file=Origin_File_Name.format(folder_num)
        original_file=os.path.join(Origin_Folder_Name,sub_folder,target_file)
        this_event_file=os.path.join(Target_Folder_Name,event_file)
        file_name_list.append(this_event_file) 
        Copy_File(original_file, this_event_file)
    return(file_name_list)

def Sort_Files_by_Time(folder):
    if(type(folder).__name__!="list"):
        dir_list = os.listdir(folder)
        if not dir_list:
            return
        else:
            # 注意，这里使用lambda表达式，将文件按照最后修改时间顺序升序排列
            # os.path.getmtime() 函数是获取文件最后修改时间
            # os.path.getctime() 函数是获取文件最后创建时间
            dir_list = sorted(dir_list,  key=lambda x: os.path.getmtime(os.path.join(folder, x)))
            return(dir_list)
    else:
        return(folder)

def Sort_Files_by_Name(folder):
    if(type(folder).__name__!="list"):
        dir_list = os.listdir(folder)
    else:
        dir_list=folder
    if not dir_list:
        return
    else:
        # 注意，这里使用lambda表达式，将文件按照最后修改时间顺序升序排列
        # os.path.getmtime() 函数是获取文件最后修改时间
        # os.path.getctime() 函数是获取文件最后创建时间
#		print(int(os.path.basename(dir_list[-1].split("_")[1])))
        dir_list = sorted(dir_list,  key=lambda x:int(os.path.basename(x).split("_")[1]) if len(x.split("."))<2 else 10000)

        return(dir_list)

# 判断一个文件是否存在
# 若pattern=""， 则之间判断输入的文件名是否存在
# 否则判断输入的文件名，是否包含pattern
def File_Exist(file_name,file_pattern=""):
    # 判断是否存在某个文件或某一类文件
    if file_pattern == "":
        # 判断某一个文件是否存在
        if os.path.exists(file_name):
            return(True)
    else:
        # 判断某一类文件是否存在
        pos=re.search(file_pattern,os.path.basename(file_name))
        if ( pos != None):
            return(True)
    return(False)

# 判断一个目录下是否存在需要的文件
# 只查找输入的目录，不查找其子目录
def File_Exist_in_a_Folder(folder_name,file_pattern=""):
    files_exist=[]
    for file in os.listdir(folder_name):
        file_dir=folder_name+"/"+file
        if File_Exist(file_dir, file_pattern):
            files_exist.append(file_dir)
    return(files_exist)


# 判断一个目录及其所有子目录下是否存在需要的文件
def File_Exist_in_Folders(folder_name,file_pattern=""):
    sub_folders=Show_All_SubFolder_Name_in_Folders(folder_name)
    files_in_all_folders=[]
    folders_not_include_file=[]
    for folder in sub_folders:
        files_in_a_folder=File_Exist_in_a_Folder(folder,file_pattern)
        files_in_all_folders.append(files_in_a_folder)
        if len(files_in_a_folder) ==0:
            folders_not_include_file.append(folder)
    Remove_Nested_List(files_in_all_folders)
    return(files_in_all_folders, folders_not_include_file)
